<?php
/**********************************************************************************
WIKINDX: Bibliographic Management system.
Copyright (C)

This program is free software; you can redistribute it and/or modify it under the terms
of the GNU General Public License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program;
if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

The WIKINDX Team 2007
sirfragalot@users.sourceforge.net
**********************************************************************************/
/*****
*	BIBTEX BibTeX export class
*****/
class BIBTEX
{
// Constructor
	function BIBTEX($db, $vars)
	{
		$this->db = $db;
		$this->vars = $vars;
		include_once("core/file/FILE.php");
		$this->file = new FILE($this->db);
		include_once("core/template/TEMPLATE.php");
		$this->template = new TEMPLATE('content');
		include_once("core/messages/ERRORS.php");
		$this->errors = new ERRORS();
		include_once("core/messages/MESSAGES.php");
		$this->messages = new MESSAGES();
		include_once("core/session/SESSION.php");
		$this->session = new SESSION();
		include_once("core/html/HTML.php");
		include_once("core/file/BIBTEXMAP.php");
		$this->map = new BIBTEXMAP();
		include_once("core/file/export/EXPORTCOMMON.php");
		$this->common = new EXPORTCOMMON($this->db);
		$this->closeNoMenu = FALSE;
		$this->pString = '';
		$this->startField = $this->endField = "\""; // default field enclosures
// Perform some system admin
		$this->file->tidyFiles();
	}
// display bibtex data for one resource (from pop-up in RESOURCEVIEW() or resource lists)
	function bibtexDisplay()
	{
		include_once("core/html/CLOSEPOPUP.php");
		include_once("core/sql/STATEMENTS.php");
		$stmt = new STATEMENTS($this->db);
// fields from WKX_resource_note, WKX_resource_category, WKX_resource_keyword and WKX_abstract:
		$array = array("text", "categories", "keywords", "abstract", "addUserIdAbstract", "editUserIdAbstract",
			"addUserIdNote", "editUserIdNote",);
		$sql = $this->db->selectNoExecute(array("WKX_resource"), array_merge($stmt->listFields(), $array),
			$stmt->selectJoin());
		$sql .= " WHERE WKX_resource.id=" . $this->db->tidyInput($this->vars['id']);
// START set up environment
// custom fields
		if(!array_key_exists('resubmit', $this->vars) && ($this->session->getArray("export") !== FALSE))
		{
			foreach($this->session->getArray("export") as $key => $value)
			{
				if(strpos($key, 'map_') == 0)
					$this->vars[$key] = $value;
			}
		}
		$metadataFields = array("quotation", "quotationComment", "paraphrase", "paraphraseComment", "musing");
		foreach($metadataFields as $field)
		{
// first time so few values in $this->vars -- check session
			if(!array_key_exists('resubmit', $this->vars) && ($value = $this->session->getVar("export_$field")))
				$this->vars[$field] = $value;
			else if(!array_key_exists('resubmit', $this->vars))
				$this->vars[$field] = '';
		}
		if(!array_key_exists('resubmit', $this->vars))
		{
			if($this->session->getVar('export_mergeStored'))
				$this->vars['mergeStored'] = TRUE;
			if($this->session->getVar('export_useOriginalCitation'))
				$this->vars['useOriginalCitation'] = TRUE;
			if($this->session->getVar('export_shortString'))
				$this->vars['shortString'] = TRUE;
			if($this->session->getVar('export_encloseField')) // braces
				$this->vars['encloseField'] = 'B';
			else // double quotes
				$this->vars['encloseField'] = 'Q';
		}
// END setup environment
		$this->process($sql);
		$this->pString = str_replace("\n", "<br />", $this->pString);
		$this->pString .= MISC::hr();
		$this->pString .= FORM::formHeader("bibtexDisplay");
		$this->pString .= FORM::hidden("id", $this->vars['id']);
		$this->pString .= FORM::hidden("resubmit", TRUE);
		$this->pString .= $this->stage1Options($sql);
		$this->template->setVar('body', $this->pString);
		new CLOSEPOPUP($this->template->process());
	}
// Stage 1 - present export options
	function stage1($error = FALSE)
	{
		include_once("core/html/TABLE.php");
		$this->template->setVar('heading', $this->messages->text("heading", "exportBibtex"));
		if(!$sql = $this->session->getVar('sql_stmt'))
			$this->failure($this->errors->text("file", "noSql"));
		$pString = $error ? $error : FALSE;
		$pString .= FORM::formHeader("exportBibtex");
		$pString .= $this->stage1Options($sql);
		$this->template->setVar('body', $pString);
		return $this->template->process();
	}
// Export/view options
	function stage1Options($sql)
	{
		$checked = $this->session->getVar("export_mergeStored") ? TRUE : FALSE;
		$pString = MISC::p($this->messages->text("misc", "mergeStored") . "&nbsp;&nbsp;" . 
			FORM::checkbox(FALSE, "mergeStored", $checked));
		$checked = $this->session->getVar("export_useOriginalCitation") ? TRUE : FALSE;
		$pString .= MISC::p($this->messages->text("misc", "useOriginalCitation") . "&nbsp;&nbsp;" . 
			FORM::checkbox(FALSE, "useOriginalCitation", $checked));
		$checked = $this->session->getVar("export_shortString") ? TRUE : FALSE;
		$pString .= MISC::p($this->messages->text("misc", "shortString") . "&nbsp;&nbsp;" . 
			FORM::checkbox(FALSE, "shortString", $checked));
		if($this->session->getVar("export_encloseField")) // TRUE == {...}
		{
			$string = FORM::radioButton(FALSE, "encloseField", "Q", FALSE) . "&nbsp;&nbsp;" . 
				$this->messages->text("misc", "bibExportQuotes");
			$string .= MISC::br() . FORM::radioButton(FALSE, "encloseField", "B", TRUE) . "&nbsp;&nbsp;" . 
				$this->messages->text("misc", "bibExportBraces");
			$pString .= MISC::p($string);
		}
		else // FALSE == "..."
		{
			$string = FORM::radioButton(FALSE, "encloseField", "Q", TRUE) . "&nbsp;&nbsp;" . 
				$this->messages->text("misc", "bibExportQuotes");
			$string .= MISC::br() . FORM::radioButton(FALSE, "encloseField", "B", FALSE) . "&nbsp;&nbsp;" . 
				$this->messages->text("misc", "bibExportBraces");
			$pString .= MISC::p($string);
		}
		$pString .= $this->common->getCustomFields($sql);
// Export metadata fields?
		$pString .= MISC::p(MISC::b($this->messages->text("misc", "exportMetadata1")) . "&nbsp;&nbsp;" . 
			$this->messages->text("misc", "exportMetadata2"));
		$pString .= TABLE::tableStart() . TABLE::trStart();
		$label = $this->messages->text("metadata", "quotes");
		$text = $this->session->getVar("export_quotation");
		$pString .= TABLE::td(FORM::textInput($label, "quotation", $text, 10));
		$label = $this->messages->text("metadata", "quoteComments");
		$text = $this->session->getVar("export_quotationComment");
		$pString .= TABLE::td(FORM::textInput($label, "quotationComment", $text, 10));
		$label = $this->messages->text("metadata", "paraphrases");
		$text = $this->session->getVar("export_paraphrase");
		$pString .= TABLE::td(FORM::textInput($label, "paraphrase", $text, 10));
		$label = $this->messages->text("metadata", "paraphraseComments");
		$text = $this->session->getVar("export_paraphraseComment");
		$pString .= TABLE::td(FORM::textInput($label, "paraphraseComment", $text, 10));
		$label = $this->messages->text("metadata", "musings");
		$text = $this->session->getVar("export_musing");
		$pString .= TABLE::td(FORM::textInput($label, "musing", $text, 10));
		$pString .= TABLE::trEnd() . TABLE::tableEnd();
		$pString .= MISC::br() . FORM::formSubmit('Submit');
		$pString .= FORM::formEnd();
		return $pString;
	}
// write $this->pString to file.
	function process($sql = FALSE)
	{
		include_once("core/user/USER.php");
		$this->user = new USER($this->db);
		if(isset($this->vars['mergeStored']))
			$this->session->setVar('export_mergeStored', $this->vars['mergeStored']);
		else
			$this->session->delVar('export_mergeStored');
		if(isset($this->vars['useOriginalCitation']))
			$this->session->setVar('export_useOriginalCitation', $this->vars['useOriginalCitation']);
		else
			$this->session->delVar('export_useOriginalCitation');
		if(isset($this->vars['shortString']))
			$this->session->setVar('export_shortString', $this->vars['shortString']);
		else
			$this->session->delVar('export_shortString');
		if(array_key_exists('encloseField', $this->vars) && $this->vars['encloseField'] == 'Q')
		{
			$this->session->setVar('export_encloseField', FALSE);
			$this->startField = "\"";
			$this->endField = "\"";
		}
		else
		{
			$this->session->setVar('export_encloseField', TRUE);
			$this->startField = "{";
			$this->endField = "}";
		}
		$this->customIds = $checkDuplicates = array();
		$duplicateMapping = FALSE;
		foreach($this->vars as $key => $value)
		{
			$split = explode("map_", $key);
			if(sizeof($split) == 2)
			{
				$value = trim($value);
				if($value)
				{
					$this->session->setVar("export_$key", $value);
					if(!$duplicateMapping && (array_search(strtolower($value), $checkDuplicates) !== FALSE))
						$duplicateMapping = TRUE;
					$this->customIds[$split[1]] = $value;
					$checkDuplicates[] = strtolower($value);
				}
				else
					$this->session->delVar("export_$key");
			}
		}
// Check for metadata input and write to session
		$metadataFields = array("quotation", "quotationComment", "paraphrase", "paraphraseComment", "musing");
		$this->metadataFields = array();
		foreach($metadataFields as $field)
		{
			$input = trim($this->vars[$field]);
			if($input)
			{
				if(($field == 'quotationComment') || ($field == 'paraphraseComment')) // may be duplicated
				{
					$this->session->setVar("export_$field", $input);
					$this->metadataFields[$field] = $input;
				}
				else if(array_search(strtolower($input), $checkDuplicates) === FALSE)
				{
					$this->session->setVar("export_$field", $input);
					$this->metadataFields[$field] = $input;
					$checkDuplicates[] = strtolower($input);
				}
				else
					$duplicateMapping = TRUE;
			}
			else
				$this->session->delVar("export_$field");
		}
		unset($checkDuplicates);
// View single entry or export list?
		if($sql)
			$this->template->setVar('heading', $this->messages->text("heading", "viewBibtex"));
		else
			$this->template->setVar('heading', $this->messages->text("heading", "exportBibtex"));
//print "$sql<P>"; die;
// if duplicate custom mapping found, fail
		if($duplicateMapping)
			$this->badInput($this->errors->text("inputError", "duplicateFieldNames"));
		$this->titleString = $this->rawString = array();
		$this->getData($sql);
		$string = array();
		if(isset($this->rawString) && !empty($this->rawString))
		{
			foreach($this->titleString as $key => $value)
			{
				if(!array_key_exists($key, $this->rawString))
					$this->rawString[$key] = $value;
			}
			foreach($this->rawString as $key => $value)
			{
				$key = preg_replace("/[^a-zA-Z0-9]/", '', $key);
				if(is_numeric($key{0}))
					$key = "string$key";
				$string[] = "@STRING" . '{' . "$key = $value" . '}';
			}
			$this->rawStringString .= implode("\n", $string) . "\n\n";
			$this->pString = $this->rawStringString . $this->pString;
		}
		else if(!empty($this->titleString))
		{
			foreach($this->titleString as $key => $value)
			{
				if($this->session->getVar("export_shortString"))
					$value = $key;
				$key = preg_replace("/[^a-zA-Z0-9]/", '', $key);
				if(is_numeric($key{0}))
					$key = "string$key";
				$string[] = "@STRING" . '{' . "$key = $value" . '}';
			}
			$this->rawStringString .= implode("\n", $string) . "\n\n";
			$this->pString = $this->rawStringString . $this->pString;
		}
// viewing a single entry?
		if($sql)
			return;
		list($fileName, $fullFileName) = $this->file->createFileName($this->pString, '.bib');
		if(!$fullFileName)
			$this->failure($this->errors->text("file", "write", ": $fileName"));
		if(!$fp = fopen("$fullFileName", "w"))
			$this->failure($this->errors->text("file", "write", ": $fileName"));
		if(!fputs($fp, $this->pString))
			$this->failure($this->errors->text("file", "write", ": $fileName"));
		fclose($fp);
		$this->common->writeFilenameToSession($fileName);
		$pString = $this->common->listFiles();
		$this->template->setVar('body', $pString);
		return $this->template->process();
	}
// get data from database
// $sql != FALSE if coming from bibtex view link in RESOURCEVIEW()
	function getData($sql = FALSE)
	{
		if(!$sql)
		{
			if(!$sql = $this->session->getVar('sql_stmt'))
				$this->failure($this->errors->text("file", "noSql"));
		}
// load default arrays
		$this->loadArrays();
		$this->stringIdArray = $this->strValues = $this->strKeys = $doneResourceIds = array();
		$this->rawStringString = '';
		$customSelect = FALSE;
		if(!empty($this->customIds))
		{
			$condition = "WHERE (" . $this->db->formatfield('customId') . "=" . 
				join(" OR " . $this->db->formatfield('customId') . "=", array_keys($this->customIds)) . ")";
			$customSelect = $this->db->selectNoExecute(array('WKX_resource_custom'), 
				array('customId', 'resourceId', 'custom_long', 'custom_short'), $condition);
		}
		$recordset = $this->db->query(stripslashes($sql));
		while($row = $this->db->loopRecordSet($recordset))
		{
			if(array_search($row['resourceId'], $doneResourceIds) !== FALSE)
				continue;
			else
				$doneResourceIds[] = $row['resourceId'];
			$this->storedBibtexKey = $row['bibtexKey'];
			$entryArray = $this->rawEntries = array();
			$this->rawCitation = $longtitle = $shorttitle = FALSE;
			$this->raw($row);
			$cite = $this->citeFormat($row);
			foreach($this->map->{$row['type']}['resource_creator'] as $wkField => $bibField)
			{
				if(!$creators = $this->nameFormat($row, $wkField, $bibField))
					continue;
				else
					$entryArray[] = $creators;
			}
			$entryArray[] = "title = " . $this->convertCharacter($this->common->titleFormat($row, TRUE));
// For book_chapter, 'title' is bibtex 'chapter' and 'collectionTitle' is bibtex 'title'
			if($row['type'] == 'book_chapter')
				$entryArray[] = "chapter = " . $this->startField . stripslashes($row['title'])
					 . $this->endField . ",";
			if(($row['type'] == 'web_article') || ($row['type'] == 'database')) // 'misc' types
			{
				$entryArray[] = "howpublished = " . $this->startField . 
					"\url{" . stripslashes($row['url']) . "}" . $this->endField . ",";
				unset($row['url']);
			}
			$pubArray = array();
// For proceedings_article, miscField1 is the publisher
			if(($row['type'] == 'proceedings_article') && $row['miscField1'])
			{
				$recordSet2 = $this->db->select(array('WKX_publisher'), array('publisherName',
					'publisherLocation'), " WHERE " . 
					$this->db->formatField("id") . "=" . $this->db->tidyInput($row['miscField1']));
				$pubArray = $this->db->fetchRow($recordSet2);
				if($pubArray['publisherName'])
					$entryArray[] = "publisher = ". 
					$this->convertCharacter(stripslashes($pubArray['publisherName']));
//				if($pubArray['publisherLocation'])
//					$entryArray[] = "address = ". 
//					$this->convertCharacter(stripslashes($pubArray['publisherLocation']));
			}
			foreach($this->map->{$row['type']} as $table => $tableArray)
			{
				if(($table == 'resource_creator') || ($table == 'howpublished'))
					continue;
				foreach($tableArray as $wkField => $bibField)
				{
					if(isset($row[$wkField]) && $row[$wkField])
					{
						if(($wkField == 'collectionTitle') && 
							isset($row['collectionTitleShort']) && 
							$row['collectionTitleShort'])
						{
							$short = stripslashes($row['collectionTitleShort']);
							$title = stripslashes($row['collectionTitle']);
							$long = preg_quote($title);
// preg_quote doesn't escape '/'
							$long = "/^" . str_replace('/', '\/', $long) . "$/";
							if(!array_key_exists($short, $this->titleString))
								$this->titleString[$short] = '"' . $title . '"';
							$entryArray[] = "$bibField = " . 
								$this->convertCharacter2($title, $short, $long);
						}
						else
							$entryArray[] = "$bibField = " . 
							$this->convertCharacter(stripslashes($row[$wkField]));
					}
				}
			}
			if($item = $this->common->pageFormat($row, 'bibtex'))
				$entryArray[] = "pages = ". $this->convertCharacter($item);
			if($item = $this->common->keywordFormat($row, 'bibtex'))
				$entryArray[] = "keywords = " . $this->convertCharacter($item);
			if($item = $this->common->grabAbstract($row, 'bibtex'))
				$entryArray[] = "abstract = " . $this->convertCharacter($this->parseCitation($item));
			if($item = $this->common->grabNote($row, 'bibtex'))
				$entryArray[] = "note = " . $this->convertCharacter($this->parseCitation($item));
// Deal with month/day
			if($row['miscField3'])
			{
				if($item = $this->formatDate($row))
// No double quotes for month
					$entryArray[] = "month = $item,";
			}
// 'howpublished'
			else if(isset($this->map->types[$row['type']]) && 
				($this->map->types[$row['type']] == 'misc') && 
				(array_key_exists('howpublished', $this->map->{$row['type']})))
			{
				$field = $this->map->{$row['type']}['howpublished'];
				if(!array_key_exists($field, $row))
					$entryArray[] = "howpublished = " . $this->convertCharacter(ucfirst($field));
				else
					$entryArray[] = "howpublished = " . $this->convertCharacter(ucfirst($row[$field]));
			}
			if(($row['type'] == 'thesis') && 
				(($row['field1'] == 'doctoral') || ($row['field1'] == 'PhD') || ($row['field1'] == 'EdD')))
				$this->pString .= "@" . 'phdthesis' . "{" . "$cite,\n\t";
			else if($row['type'] == 'thesis') // masters + unknown
				$this->pString .= "@" . 'mastersthesis' . "{" . "$cite,\n\t";
			else
				$this->pString .= "@" . $this->map->types[$row['type']] . "{" . "$cite,\n\t";
			if($this->session->getVar("export_mergeStored") && !empty($this->rawEntries))
			{
				foreach($this->rawEntries as $key => $value)
				{
					if(($key == 'month') && ($value{0} == '"'))
					{
						$value = substr($value, 1);
						$value = substr($value, 0, -1);
					}
					$entryArray[] = $key . " = " . $value . ",";
				}
			}
// Deal with any custom field mappings
			if($customSelect)
			{
				$customset = $this->db->query($customSelect . " AND " . 
					$this->db->formatfield('resourceId') . '=' . $row['resourceId']);
				while($customRow = $this->db->loopRecordSet($customset))
				{
					if($customRow['custom_short'])
						$entryArray[] = $this->customIds[$customRow['customId']] . " = " . 
						$this->convertCharacter(stripslashes($customRow['custom_short']));
					if($customRow['custom_long'])
						$entryArray[] = $this->customIds[$customRow['customId']] . " = " . 
						$this->convertCharacter(stripslashes($customRow['custom_long']));
				}
			}
// Deal with metadata
			$this->userId = $this->session->getVar("setup_userId");
			if(array_key_exists('quotation', $this->metadataFields))
				$this->getMetadataQ($row['resourceId'], $entryArray);
			if(array_key_exists('paraphrase', $this->metadataFields))
				$this->getMetadataP($row['resourceId'], $entryArray);
			if(array_key_exists('musing', $this->metadataFields))
				$this->getMetadataM($row['resourceId'], $entryArray);
// remove final ',' from last field
			$lastEntryIndex = sizeof($entryArray) - 1;
			$entryArray[$lastEntryIndex] = 
				substr($entryArray[$lastEntryIndex], 0, strlen($entryArray[$lastEntryIndex]) - 1);
			$this->pString .= join("\n\t", $entryArray) . "\n}\n\n";
		}
	}
/* 
* Get any requested metadata (quotations)
*/
	function getMetadataQ($resourceId, &$entryArray)
	{
		$recordset = $this->db->select(array('WKX_resource_quote'), 
			array(array('WKX_resource_quote.id' => 'quoteId'), 
				'page_start', 'page_end', 'text'), 
			" LEFT JOIN " . $this->db->formatTable('WKX_resource_quote_text') . 
			" ON " . $this->db->formatField("WKX_resource_quote.id") . "=" . 
			$this->db->formatField("WKX_resource_quote_text.id") . 
			" WHERE " . $this->db->formatField("WKX_resource_quote.resourceId") . "=" . 
			$this->db->tidyInput($resourceId) . 
			" ORDER BY " . $this->db->tidyInputClause('page_start') . ' + 0');
		if($this->db->numRows($recordset) > 1)	
			$index = 1;
		else
			$index = FALSE;
		while($row = $this->db->loopRecordSet($recordset))
		{
			if($row['page_start'])
			{
				$pages = $row['page_start'];
				if($row['page_end'])
					$pages = '(pp.' . $pages . '-' . $row['page_end'] . ') ';
				else
					$pages = "(p.$pages) ";
			}
			else
				$pages = FALSE;
			$text = stripslashes($pages . $row['text']);
			if($index)
			{
				$fieldNameQ = $this->metadataFields['quotation'] . "_$index";
				$index++;
			}
			else
				$fieldNameQ = $this->metadataFields['quotation'];
			$entryArray[] = $fieldNameQ . ' = ' . 
				$this->convertCharacter($this->parseCitation($text));
// Grab any quote comments
			if(array_key_exists('quotationComment', $this->metadataFields))
			{
				$recordset2 = $this->db->select(array('WKX_resource_quote_comment'),
					array('comment', 'addUserIdQuote'), 
					" WHERE " . $this->db->formatField('quoteId') . "=" . 
					$this->db->tidyInput($row['quoteId']) . 
					" AND (" . 
					$this->db->formatfield("addUserIdQuote") . "=" . 
					$this->db->tidyInput($this->userId) . 
					" OR " . 
					$this->db->formatfield("quotePrivate") . "=" . 
					$this->db->tidyInput('N') . ")"
				);
				if($this->db->numRows($recordset2) > 1)	
					$indexC = 1;
				else
					$indexC = FALSE;
				while($rowC = $this->db->loopRecordSet($recordset2))
				{
					if($indexC)
					{
						$fieldName = $fieldNameQ . "_" . $this->metadataFields['quotationComment'] . "_$indexC";
						$indexC++;
					}
					else
						$fieldName = $fieldNameQ . "_" . $this->metadataFields['quotationComment'];
					$user = " (" . $this->user->displayUserAddEditPlain($rowC['addUserIdQuote']) . ")";
					$text = stripslashes($rowC['comment']);
					$entryArray[] = $fieldName . ' = ' . 
						$this->convertCharacter($this->parseCitation($text) . $user);
				}
			}
		}
	}
/* 
* Get any requested metadata (paraphrases)
*/
	function getMetadataP($resourceId, &$entryArray)
	{
		$recordset = $this->db->select(array('WKX_resource_paraphrase'), 
			array(array('WKX_resource_paraphrase.id' => 'paraphraseId'), 
				'page_start', 'page_end', 'text'), 
			" LEFT JOIN " . $this->db->formatTable('WKX_resource_paraphrase_text') . 
			" ON " . $this->db->formatField("WKX_resource_paraphrase.id") . "=" . 
			$this->db->formatField("WKX_resource_paraphrase_text.id") . 
			" WHERE " . $this->db->formatField("WKX_resource_paraphrase.resourceId") . "=" . 
			$this->db->tidyInput($resourceId) . 
			" ORDER BY " . $this->db->tidyInputClause('page_start') . ' + 0');
		if($this->db->numRows($recordset) > 1)	
			$index = 1;
		else
			$index = FALSE;
		while($row = $this->db->loopRecordSet($recordset))
		{
			if($row['page_start'])
			{
				$pages = $row['page_start'];
				if($row['page_end'])
					$pages = '(pp.' . $pages . '-' . $row['page_end'] . ') ';
				else
					$pages = "(p.$pages) ";
			}
			else
				$pages = FALSE;
			$text = stripslashes($pages . $row['text']);
			if($index)
			{
				$fieldNameQ = $this->metadataFields['paraphrase'] . "_$index";
				$index++;
			}
			else
				$fieldNameQ = $this->metadataFields['paraphrase'];
			$entryArray[] = $fieldNameQ . ' = ' . 
				$this->convertCharacter($this->parseCitation($text));
// Grab any quote comments
			if(array_key_exists('quotationComment', $this->metadataFields))
			{
				$recordset2 = $this->db->select(array('WKX_resource_paraphrase_comment'),
					array('comment', 'addUserIdParaphrase'), 
					" WHERE " . $this->db->formatField('paraphraseId') . "=" . 
					$this->db->tidyInput($row['paraphraseId']) . 
					" AND (" . 
					$this->db->formatfield("addUserIdParaphrase") . "=" . 
					$this->db->tidyInput($this->userId) . 
					" OR " . 
					$this->db->formatfield("paraphrasePrivate") . "=" . 
					$this->db->tidyInput('N') . ")"
				);
				if($this->db->numRows($recordset2) > 1)	
					$indexC = 1;
				else
					$indexC = FALSE;
				while($rowC = $this->db->loopRecordSet($recordset2))
				{
					if($indexC)
					{
						$fieldName = $fieldNameQ . "_" . $this->metadataFields['paraphraseComment'] . "_$indexC";
						$indexC++;
					}
					else
						$fieldName = $fieldNameQ . "_" . $this->metadataFields['paraphraseComment'];
					$user = " (" . $this->user->displayUserAddEditPlain($rowC['addUserIdParaphrase']) . ")";
					$text = stripslashes($rowC['comment']);
					$entryArray[] = $fieldName . ' = ' . 
						$this->convertCharacter($this->parseCitation($text) . $user);
				}
			}
		}
	}
/* 
* Get any requested metadata (musing)
*/
	function getMetadataM($resourceId, &$entryArray)
	{
		$recordset = $this->db->select(array('WKX_resource_musing'), 
			array('page_start', 'page_end', 'text', 'addUserIdMusing'), 
			" LEFT JOIN " . $this->db->formatTable('WKX_resource_musing_text') . 
			" ON " . 
			$this->db->formatfield("WKX_resource_musing.id") . "=" . 
			$this->db->formatfield("WKX_resource_musing_text.id") . 
			" WHERE " . $this->db->formatfield("WKX_resource_musing.resourceId") . "=" . 
			$this->db->tidyInput($resourceId) . 
			" AND (" . 
			$this->db->formatfield("WKX_resource_musing_text.addUserIdMusing") . "=" . 
			$this->db->tidyInput($this->userId) . 
			" OR " . 
			$this->db->formatfield("WKX_resource_musing_text.musingPrivate") . "=" . 
			$this->db->tidyInput('N') . 
			") ORDER BY " . $this->db->tidyInputClause('page_start') . ' + 0');
		if($this->db->numRows($recordset) > 1)	
			$index = 1;
		else
			$index = FALSE;
		while($row = $this->db->loopRecordSet($recordset))
		{
			if($row['page_start'])
			{
				$pages = $row['page_start'];
				if($row['page_end'])
					$pages = '(pp.' . $pages . '-' . $row['page_end'] . ') ';
				else
					$pages = "(p.$pages) ";
			}
			else
				$pages = FALSE;
			$text = stripslashes($pages . $row['text']);
			if($index)
			{
				$fieldNameQ = $this->metadataFields['musing'] . "_$index";
				$index++;
			}
			else
				$fieldNameQ = $this->metadataFields['musing'];
			$user = " (" . $this->user->displayUserAddEditPlain($row['addUserIdMusing']) . ")";
			$entryArray[] = $fieldNameQ . ' = ' . 
				$this->convertCharacter($this->parseCitation($text) . $user);
		}
	}
/*
* For bibtex exports, return bibtex key instead of formatted citation for citations within the body of text
*/
	function parseCitation($text)
	{
// If no citations, return doing nothing
		if(strpos(strtolower($text), "[cite]") === FALSE)
			return $text;
// Capture any text after last [cite]...[/cite] tag
		$explode = explode("]etic/[", strrev($text), 2);
		$tailText = strrev($explode[0]);
		$text = strrev("]etic/[" . $explode[1]);
//print $this->tailText . "<P>";
		preg_match_all("/(.*)\s*\[cite\](.*)\[\/cite\]/Uis", $text, $match);
		return preg_replace_callback("/(\[cite\])(.*)(\[\/cite\])/Uis", array($this, "citeCallback"), 
			$text . $tailText);
	}
/**
* Callback for citations
*/
	function citeCallback($matches)
	{
		array_shift($matches);
		return $this->parseCiteTag($matches[1]);
	}
/**
* Parse the cite tag by extracting resource ID and any page numbers. Check ID is valid
* PreText and postText can also be encoded: e.g. (see Grimshaw 2003; Boulanger 2004 for example)
* [cite]23:34-35|see ` for example[/cite].  For multiple citations, only the first encountered preText and postText will be used to enclose the citations.
*/
	function parseCiteTag($cite)
	{
		$rawCitation = explode("|", $cite);
		$idPart = explode(":", $rawCitation[0]);
		$id = $idPart[0];
		$resultset = $this->db->select(array("WKX_resource"), array('id') , 
			" WHERE " . $this->db->formatField('id') . "=" . $this->db->tidyInput($id));
// Presumably an invalid citation ID
		if(!$this->db->numRows($resultset))
			return "INVALID CITATION";
		$citeKey = "WIKINDXCITEKEYSTART" . $this->citeBibtexKey($id) . "WIKINDXCITEKEYEND";
		if(array_key_exists('1', $idPart))
		{
			$pages = explode("-", $idPart[1]);
			$pageStart = $pages[0];
			$pageEnd = array_key_exists('1', $pages) ? $pages[1] : FALSE;
			if($pageEnd)
				$pages = " pp.$pageStart-$pageEnd";
			else
				$pages = " p.$pageStart";
		}
		else
			$pages = FALSE;
		if(array_key_exists('1', $rawCitation))
		{
			$text = explode("`", $rawCitation[1]);
			$preText = $text[0];
			$postText = array_key_exists('1', $text) ? $text[1] : FALSE;
		}
		else
			$preText = $postText = FALSE;
		return "$preText$citeKey$pages$postText";
	}
/**
* For citations, get the bibtex key
*/
	function citeBibtexKey($id)
	{
		if($this->session->getVar("setup_useBibtexKey"))
		{
			$recordset = $this->db->select(array('WKX_import_raw'), array('text'), 
				"WHERE " . $this->db->formatField('id') . "=" . $this->db->tidyInput($id) . 
				" AND " . $this->db->formatField('importType') . "=" . $this->db->tidyInput('bibtex'));
			$rawEntries = unserialize(base64_decode($this->db->fetchOne($recordset)));
			if($rawEntries)
			{
				$rawEntries = explode("\n", $rawEntries);
				array_pop($rawEntries); // always an empty array at end so get rid of it.
				foreach($rawEntries as $entries)
				{
					$entry = explode("=", $entries, 2);
					if(!trim($entry[1]))
						continue;
					if(trim($entry[0]) == 'citation')
						return trim($entry[1]);
				}
			}
		}
		if(!$this->session->getVar("setup_useWikindxKey"))
			return $this->storedBibtexKey;
// Use wikindx=generated keys from this point on
// Get creator 1 and creator 2 for this ID
		$creator1 = $creator2 = FALSE;
		$recordset = $this->db->select(array('WKX_resource_creator'), array('creator1', 'creator2'), 
			" WHERE " . $this->db->formatField('id') . "=" . $this->db->tidyInput($id));
		while($row = $this->db->loopRecordSet($recordset))
		{
			if($row['creator1'])
			{
				$split = split(',', $row['creator1']);
				$creator1 = $split[0];
			}
			else if($row['creator2'])
			{
				$split = split(',', $row['creator2']);
				$creator2 = $split[0];
			}
		}
		if($creator1)
		{
			$recordset = $this->db->select(array('WKX_creator'), array('surname'), 
				" WHERE " . $this->db->formatField('id') . "=" . 
				$this->db->tidyInput($creator1));
			$name = $this->db->fetchRow($recordset);
			$cite = $this->convertCharacter(stripslashes($name['surname']), 'plain');
			$cite = preg_replace("/\W/", '', $cite);
		}
		else if($creator2)
		{
			$recordset = $this->db->select(array('WKX_creator'), array('surname'), 
				" WHERE " . $this->db->formatField('id') . "=" . 
				$this->db->tidyInput($creator2));
			$name = $this->db->fetchRow($recordset);
			$cite = $this->convertCharacter(stripslashes($name['surname']), 'plain');
			$cite = preg_replace("/\W/", '', $cite);
		}
		else
			$cite = 'anon';
		return $cite . '.' . $id;
	}
// grab any stored data and @strings for this resource from WKX_import_raw
	function raw($row)
	{
		$recordset = $this->db->select(array('WKX_import_raw'), array('text', 'stringId', 'importType'), 
			"WHERE " . $this->db->formatField('id') . "=" . $this->db->tidyInput($row['resourceId']) . 
			" AND " . $this->db->formatField('importType') . "=" . $this->db->tidyInput('bibtex'));
		if(!$this->db->numRows($recordset))
			return;
		$stringIdFound = FALSE;
		while($rawRow = $this->db->loopRecordSet($recordset))
		{
			$rawEntries = unserialize(base64_decode($rawRow['text']));
			foreach($this->stringIdArray as $stringId)
			{
				if($rawRow['stringId'] == $stringId)
				{
					$stringIdFound = TRUE;
					break;
				}
			}
			if($stringIdFound)
				break;
			if(array_search($rawRow['stringId'], $this->stringIdArray) === FALSE)
			{
				$recordset = $this->db->select(array('WKX_bibtex_string'), array('text'), 
					"WHERE " . $this->db->formatField('id') . "=" . 
					$this->db->tidyInput($rawRow['stringId']));
				$rawString = unserialize(base64_decode($this->db->fetchOne($recordset))) . "\n\n";
				if($rawString)
					preg_match_all("/@STRING{(.*)}/", $rawString, $strings);
				foreach($strings[1] as $string)
				{
					$split = explode("=", $string, 2);
					$key = trim($split[0]);
					if(array_search($key, $this->rawString) === FALSE)
						$this->rawString[$key] = trim($split[1]);
				}
				$this->orderArrayByKeyLength();
				foreach($this->rawString as $key => $value)
				{
					if(preg_match("/^[\"{](.*)[\"}]$/", trim($value), $matches))
						$value = $matches[1];
					$value = "/^" . preg_quote($value, "/") . "$/";
					if(!array_search($value, $this->strValues))
						$this->strValues[] = $value;
					if(!array_search($key, $this->strKeys))
						$this->strKeys[] = $key;
				}
				$this->stringIdArray[] = $rawRow['stringId'];
				break;
			}
		}
		$this->strValues = array_unique($this->strValues);
		$this->strKeys = array_unique($this->strKeys);
		if($rawEntries)
		{
			$rawEntries = explode("\n", $rawEntries);
			array_pop($rawEntries); // always an empty array at end so get rid of it.
			foreach($rawEntries as $entries)
			{
				$entry = explode("=", $entries, 2);
				if(!trim($entry[1]))
					continue;
				if(trim($entry[0]) == 'citation')
					$this->rawCitation = trim($entry[1]);
				else
				{
					$key = trim($entry[0]);
					$value = trim($entry[1]);
					if($this->startField == "{")
					{
						$match = "/^(\")(.*)(\")$/";
						if(preg_match($match, $value, $matches))
							$value = $this->startField . $matches[2] . $this->endField;
					}
					else if($this->startField == "\"")
					{
						$match = "/^(\{)(.*)(\})$/";
						if(preg_match($match, $value, $matches))
							$value = $this->startField . $matches[2] . $this->endField;
					}
					$this->rawEntries[$key] = $value;
				}
			}
		}
	}
// convert special characters to TeX codes
	function convertTex($string, $type = FALSE)
	{
// As web browser encoding is set to UTF-8, all input in the db is stored as UTF-8 - convert back to ISO-8859-1
		$c = utf8_decode($string);
		if($type == 'plain')
		{
			foreach($this->spChPlain as $key => $value)
			{
				$char = chr($key);
        			$c = preg_replace("/$char/", "$value", $c);
			}
		}
		else
		{
// '\' and '$' are special cases and must be treated separately.  Former MUST be treated first!
			$char = "\\" . chr(0x005C);	// '\'
			$rep = "\\textbackslash";
			$c = preg_replace("/$char/", $rep, $c);
//			$char = "\\" . chr(0x0024);	// '$'
//			$rep = "\\textdollar";
//			$c = preg_replace("/$char/", $rep, $c);
			foreach($this->spCh as $key => $value)
			{
				$match[] = "/" . preg_quote(chr($key)) . "/";
				$replace[] = $value;
			}
        	$c = preg_replace($match, $replace, $c);
		}
// Convert some BBCode and any citeKeys to TeX and strip the rest
		$bbCode = array(
							"/\[b\](.*?)\[\/b\]/si",
							"/\[u\](.*?)\[\/u\]/si",
							"/\[i\](.*?)\[\/i\]/si",
							"/\[sup\](.*?)\[\/sup\]/si",
							"/\[sub\](.*?)\[\/sub\]/si",
							"/WIKINDXCITEKEYSTART(.*?)WIKINDXCITEKEYEND/si",
			);
		$tex = array(
							"\\textbf{\\1}",
							"\\underline{\\1}",
							"\\textit{\\1}",
							"^{\\1}",
							"_{\\1}",
							"\\cite{\\1}",
			);
		$c = preg_replace($bbCode, $tex, $c);
		return HTML::stripBBCode($c);
	}
// convert @STRING from raw database @string fields.
	function convertCharacter($string, $type = FALSE)
	{
		$c = $this->convertTex($string, $type);
// Do @string substitutions
		if(!empty($this->strValues))
		{
			$replace = preg_replace($this->strValues, $this->strKeys, $c);
// If a replacement has occurred, $replace != $c so return without quotes
			if($replace != $c)
			{
				$replace = preg_replace("/[^a-zA-Z0-9]/", '', $replace);
				if(is_numeric($replace{0}))
					$replace = "string$replace";
				return $replace . ",";
			}
		}
// no replacement so return quoted unless value is an integer
//		if(is_numeric($c))
//			return $c . ",";
		return $this->startField . $c . $this->endField . ",";
	}
// convert @string from WIKINDX stored fields
	function convertCharacter2($string, $replace, $pattern, $type = FALSE)
	{
		$c = $this->convertTex($string, $type);
// Do @string substitutions
		$replace = preg_replace($pattern, $replace, $c);
// If a replacement has occurred, $replace != $c so return without quotes
		if($replace != $c)
		{
			$replace = preg_replace("/[^a-zA-Z0-9]/", '', $replace);
			if(is_numeric($replace{0}))
				$replace = "string$replace";
			return $replace . ",";
	}
// no replacement so return quoted unless value is an integer
//		if(is_numeric($c))
//			return $c . ",";
		return $this->startField . $c . $this->endField . ",";
	}
// load default arrays
	function loadArrays()
	{
// need to use English constants for BibTeX
		include_once("languages/en/CONSTANTS.php");
		$constants = new CONSTANTS_en();
		include_once("core/file/BIBTEXCONFIG.php");
		$config = new BIBTEXCONFIG();
		$config->bibtex();
		$temp = $config->bibtexSpCh;
// We need to remove first two elements of array as we don't want to convert '{' and '}'. Because the keys of the original 
// array are hexadecimal characters, this means array_shift will treat them as integer keys and will modify the array 
// keys - we don't want this!
		$index = 0;
		foreach($temp as $key => $value)
		{
			if($index >= 2)
				$this->spCh[$key] = $value;
			$index++;
		}
		$this->spChPlain = $config->bibtexSpChPlain;
		$constants->convertNumbers();
		$this->editionArray = $constants->cardinalToOrdinalWord();
		$this->monthArray = $constants->monthToLongName();
	}
// store surname of first author for BibTeX citation purposes.
// $this->cite[] holds existing citations which must not be repeated.
// Ensure $cite has no spaces, commas etc.
	function citeFormat($row)
	{
		if(!isset($this->cite))
			$this->cite = array();
		if(($this->session->getVar("setup_useBibtexKey")) && 
			$this->rawCitation && !array_key_exists($this->rawCitation, $this->cite))
		{
			$this->cite[] = $this->rawCitation;
			return trim($this->rawCitation);
		}
		if(!$this->session->getVar("setup_useWikindxKey"))
			return $this->storedBibtexKey;
// Use wikindx=generated keys from this point on
		if($row['creator1'])
		{
			$recordset = $this->db->select(array('WKX_creator'), array('surname'), 
				" WHERE " . $this->db->formatField('id') . "=" . 
				$this->db->tidyInput($row['creator1']));
			$name = $this->db->fetchRow($recordset);
			$cite = $this->convertCharacter(stripslashes($name['surname']), 'plain');
			$cite = preg_replace("/\W/", '', $cite);
		}
		else if($row['creator2'])
		{
			$recordset = $this->db->select(array('WKX_creator'), array('surname'), 
				" WHERE " . $this->db->formatField('id') . "=" . 
				$this->db->tidyInput($row['creator2']));
			$name = $this->db->fetchRow($recordset);
			$cite = $this->convertCharacter(stripslashes($name['surname']), 'plain');
			$cite = preg_replace("/\W/", '', $cite);
		}
		else
			$cite = 'anon';
/*
		for($i = 1; $i < 100000; $i++)
		{
			if(!array_key_exists($cite . '.' . $i, $this->cite))
			{
				$this->cite[$cite . '.' . $i] = FALSE;
				break;
			}
		}
*/
//  JDS suggestion for generating unique and consistent bibtex keys for every export.
		return $cite . '.' . $row['resourceId'];
	}
// format names.
	function nameFormat($row, $type, $bibField)
	{
		if(!$row[$type])
			return;
		$creatorIds = explode(",", $row[$type]);
		foreach($creatorIds as $id)
			$condition[] = $this->db->formatField('id') . "=" . $this->db->tidyInput($id);
		$recordset = $this->db->select(array('WKX_creator'), 
			array('surname', 'firstname', 'initials', 'prefix', 'id'), 
			" WHERE " . implode(' OR ', $condition));
		while($creatorRow = $this->db->loopRecordSet($recordset))
		{
			$name = $this->common->formatName($creatorRow, 'bibtex');
			if($name)
				$mapName[$creatorRow['id']] = $name;
		}
		foreach($creatorIds as $id)
			$nameArray[] = $mapName[$id];
		if(isset($nameArray))
			return $bibField . " = " . $this->convertCharacter(join(' and ', $nameArray));
	}
// Deal with month/day
	function formatDate($row)
	{
// NB 3-letter month abbreviation must not be quoted
		if(!$row['miscField3'])
			return '';
		$startMonth = $this->monthArray[$row['miscField3']];
// if there's a day, append it
		if($row['miscField2'])
			$startDay = $this->startField . " " . $row['miscField2'] . $this->endField;
		if(isset($startDay) && $row['miscField5'] && $row['miscField6'] && 
			($row['miscField3'] == $row['miscField6']))
			$date = $this->startField . $startMonth . $this->endField . " # "
				. $this->startField . $row['miscField2'] 
				. "--" . $row['miscField5'] . $this->endField;
		else if(isset($startDay) && $row['miscField5'] && $row['miscField6'])
			$date = $this->startField . $startMonth . $this->endField . " # " 
			. $this->startField . $row['miscField2'] . "--" . 
			$this->endField . " # " . $this->startField . $this->monthArray[$row['miscField6']] 
			. $this->endField . " # " . $this->startField . $row['miscField5'] . $this->endField;
		else if($row['miscField6'])
			$date = $this->startField . $startMonth . $this->endField . " # " 
			. $this->startField . "/" . $this->endField . 
			" # " . $this->startField . $this->monthArray[$row['miscField6']] . $this->endField;
		else if(isset($startDay))
			$date = $this->startField . $startMonth . $this->endField . " # " 
			. $this->startField . $startDay . $this->endField;
		else
			$date = $this->startField . $startMonth . $this->endField;
		return $date;
	}
// Error handling
	function failure($error)
	{
		$this->template->setVar('body', $error);
		$pString = $this->template->process();
		include_once("core/html/CLOSE.php");
		new CLOSE($this->db, $pString);
	}
// Error handling
	function badInput($error)
	{
		if($this->closeNoMenu)
		{
			$this->template->setVar('heading', $this->messages->text("heading", "exportBibtex"));
			$this->template->setVar('body', $error);
			include_once("core/html/CLOSENOMENU.php");
			new CLOSENOMENU($this->db, $this->template->process());
		}
		include_once("core/html/CLOSE.php");
		new CLOSE($this->db, $this->stage1($error));
	}
	function orderArrayByKeyLength()
	{
		uksort($this->rawString, array($this, "cmp"));
	}
// user function for uksort above
	function cmp($a, $b)
	{
		if(preg_match_all("/./", $a, $throwAway) > preg_match_all("/./", $b, $throwAway2))
			return 0;
		return preg_match_all("/./", $a, $throwAway) > preg_match_all("/./", $b, $throwAway2) ? -1 : 1;
	}
}
?>
